package com.yfbao.horizon.sacn;

import cn.hutool.core.io.FileUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.RestController;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
import sun.util.calendar.BaseCalendar;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.nio.charset.Charset;
import java.util.*;
import java.util.stream.Collectors;

public class ScanClass {


    private static int defaultListSize=1000;
    private static int defauleMapSize = 1000;
    private static int defaultPageSize = 100;

    private static Map<String,Integer> recursionMap = new HashMap<>();
    private static String baseDir = "C:\\Users\\byf78\\Desktop\\日志分析\\接口流量测算";
    private static String excelName = "2.8-api.xls";
//    private static String excelName = "org-out.xls";
    private static String[] perfixArray = new String[]{"ctp-user","organization","app-common"};

    public static void main(String[] args) throws Exception {
        String file ="C:\\Users\\byf78\\Desktop\\日志分析\\接口流量测算\\jar";
        String prefix = "ctp-user";

//        String file ="C:\\Users\\byf78\\Desktop\\日志分析\\接口流量测算\\organization-assemble";
//        String prefix = "organization";
        scanTarClass(file,prefix);
    }

    private static void scanTarClass(String file,String prefix) throws Exception {
        Set<String> set = ClassHelper.scanAndGetTargetClassSet(file, prefix);
        sacnInterface(file);

//        scanController(set);
//        scanDubboService(set);
    }



    private static void sacnInterface(String file){
        try {
            List<ApiMethodVo> statList = new ArrayList<>();
            for (String prefix : perfixArray) {
                Set<String> set = ClassHelper.scanAndGetTargetClassSet(file, prefix);
                List<ApiMethodVo> apiMethodVos = scanControllerApi(set);
                for (ApiMethodVo apiMethodVo : apiMethodVos) {
                    apiMethodVo.setServiceName(prefix);
                }
                statList.addAll(apiMethodVos);
            }
            writeToFile(statList,baseDir+ File.separator+"rest-api");
            statList.clear();
            for (String prefix : perfixArray) {
                Set<String> set = ClassHelper.scanAndGetTargetClassSet(file, prefix);
                List<ApiMethodVo> apiMethodVos = scanDubboApi(set);
                for (ApiMethodVo apiMethodVo : apiMethodVos) {
                    apiMethodVo.setServiceName(prefix);
                }
                statList.addAll(apiMethodVos);
            }
            writeToFile(statList,baseDir+ File.separator+"dubbo-api");

        } catch (Exception e) {
            System.out.println("sacn exception");
            e.printStackTrace();
        }
    }

    private static List<ApiMethodVo>  scanControllerApi(Set<String> set) throws Exception {
        Set<Class<?>> restAnnotaitonClazzFromSet = ClassHelper.getTargetAnnotaitonClazzFromSet(set, RestController.class);
        System.out.println("RestController class size:"+restAnnotaitonClazzFromSet.size());
        List<ApiMethodVo> statList = new ArrayList<>();
        for (Class<?> aClass : restAnnotaitonClazzFromSet) {
            String classApiValue = getClassAnnotationValue(aClass,RestController.class);
            getAnnotationByMethods(classApiValue,aClass, RestController.class,statList);
        }
        return statList;
//        writeToFile(statList,baseDir+ File.separator+"rest-api");
    }

    private static List<ApiMethodVo>  scanDubboApi(Set<String> set) throws Exception {
        Set<Class<?>> dubboAnnotaitonClazzFromSet = ClassHelper.getTargetAnnotaitonClazzFromSet(set, RestController.class);
        System.out.println("Dubbo class size:"+dubboAnnotaitonClazzFromSet.size());
        List<ApiMethodVo> statList = new ArrayList<>();
        for (Class<?> aClass : dubboAnnotaitonClazzFromSet) {
            String classApiValue = getClassAnnotationValue(aClass, RestController.class);
            getDubboApiMethodsInfo(classApiValue,aClass,statList);
        }
        return statList;
//        writeToFile(statList,baseDir+ File.separator+"dubbo-api");
    }


    private static void scanController(Set<String> set) throws Exception {
        Set<Class<?>> restAnnotaitonClazzFromSet = ClassHelper.getTargetAnnotaitonClazzFromSet(set, RestController.class);
        System.out.println("RestController class size:"+restAnnotaitonClazzFromSet.size());
        List<ClassMethodStat> statList = new ArrayList<>();
        for (Class<?> aClass : restAnnotaitonClazzFromSet) {
            getAnnotationByMethodsAndResLength(aClass, RestController.class,statList);
        }
        writeToFile(statList,baseDir+ File.separator+"rest-out");
    }

    private static void scanDubboService(Set<String> set) throws Exception {
        Set<Class<?>> dubboAnnotaitonClazzFromSet = ClassHelper.getTargetAnnotaitonClazzFromSet(set, RestController.class);
        System.out.println("Dubbo class size:"+dubboAnnotaitonClazzFromSet.size());
        List<ClassMethodStat> statList = new ArrayList<>();
        for (Class<?> aClass : dubboAnnotaitonClazzFromSet) {
            getByMethodsAndResLength(aClass,statList);
        }
        writeToFile(statList,baseDir+ File.separator+"dubbo-out");
    }



    public static void getDubboApiMethodsInfo(String classInfo, Class<?> aClass, List<ApiMethodVo> statList) throws Exception {
        List<Method> metohdsOutObjectMethods = getMetohdsOutObjectMethods(aClass);
//        Method[] methods = aClass.getMethods();
        for (Method method : metohdsOutObjectMethods) {
            if(method.getName().startsWith("lambda") && method.getName().contains("$")){
                System.out.println("跳过代理的方法："+method.getName());
                continue;
            }
            Annotation metodAnnotations = ClassHelper.getMetodAnnotations(method, RestController.class);
            if(metodAnnotations ==null){
                continue;
            }

            ApiMethodVo classMethodStat = new ApiMethodVo();
            classMethodStat.setClassName(aClass.getName());
            classMethodStat.setClassSimpleName(aClass.getSimpleName());
            classMethodStat.setMethodName(method.getName());
            classMethodStat.setReturnValueType(method.getGenericReturnType().getTypeName());
            classMethodStat.setClassDesc(classInfo);
//            Class<?>[] parameterTypes = method.getParameterTypes();
            Type[] genericParameterTypes = method.getGenericParameterTypes();
            ArrayList<String> list = new ArrayList<>();
//            for (Class<?> parameterType : parameterTypes) {
//                list.add(parameterType.getTypeName());
//            }
            for (Type genericParameterType : genericParameterTypes) {
                list.add(genericParameterType.getTypeName());
            }
            classMethodStat.setParams(list);

            Class<? extends Annotation> annotationClz = metodAnnotations.getClass();
            Method valueMethod = annotationClz.getMethod("value");
            if(valueMethod!=null){
                Object value= valueMethod.invoke(metodAnnotations);
                classMethodStat.setMethodFunctionDesc(String.valueOf(value));
            }

            Method descriptionMethod = annotationClz.getMethod("description");
            if(descriptionMethod !=null){
                Object description= descriptionMethod.invoke(metodAnnotations);
                classMethodStat.setMethodDesc(String.valueOf(description));
            }

            Method returnValueMethod = annotationClz.getMethod("returnValue");
            if(returnValueMethod!=null){
                Object returnValue= returnValueMethod.invoke(metodAnnotations);
                classMethodStat.setReturnDesc(String.valueOf(returnValue));
            }


            Method openApiMethod = annotationClz.getMethod("openApi");
            if(openApiMethod!=null){
                Object openApi = openApiMethod.invoke(metodAnnotations);
                Method url1 = openApi.getClass().getMethod("url");
                if(url1!=null){
                    Object url = url1.invoke(openApi);
                    if(StringUtils.isNotBlank(String.valueOf(url))){
                        classMethodStat.setUrl(String.valueOf(url));
                        classMethodStat.setOpenApi(true);
                    }
                }
            }

            statList.add(classMethodStat);
        }
    }


    public static void getByMethodsAndResLength(Class<?> aClass, List<ClassMethodStat> statList) throws Exception {
        List<Method> metohdsOutObjectMethods = getMetohdsOutObjectMethods(aClass);
//        Method[] methods = aClass.getMethods();
        for (Method method : metohdsOutObjectMethods) {
            if(method.getName().startsWith("lambda") && method.getName().contains("$")){
                System.out.println("跳过代理的方法："+method.getName());
                continue;
            }
            ClassMethodStat classMethodStat = new ClassMethodStat();
            classMethodStat.setClassName(aClass.getSimpleName());
            classMethodStat.setMethodName(method.getName());
            classMethodStat.setReturnValueType(method.getGenericReturnType().getTypeName());
            System.out.println("开始处理类："+aClass.getSimpleName()+", 方法："+method.getName());
            long methodResLength = getMethodResLength(method);
            System.out.println("完成处理类："+aClass.getSimpleName()+", 方法："+method.getName()+", 返回值长度评估:"+methodResLength);
            classMethodStat.setReturnLength(methodResLength);
            statList.add(classMethodStat);
        }
    }

    public static <A extends Annotation> void getAnnotationByMethodsAndResLength(Class<?> aClass, Class<A> annotationClass, List<ClassMethodStat> statList) throws Exception {
        Method[] methods = aClass.getMethods();
        for (Method method : methods) {
            if(method.getName().startsWith("lambda") && method.getName().contains("$")){
                System.out.println("跳过代理的方法："+method.getName());
                continue;
            }
            ClassMethodStat classMethodStat = new ClassMethodStat();
            classMethodStat.setClassName(aClass.getSimpleName());
            classMethodStat.setMethodName(method.getName());
            classMethodStat.setReturnValueType(method.getGenericReturnType().getTypeName());
            if(annotationClass ==null){
                long methodResLength = getMethodResLength(method);
                System.out.println("完成处理类："+aClass.getSimpleName()+", 方法："+method.getName()+", 返回值长度评估:"+methodResLength);
                classMethodStat.setReturnLength(methodResLength);
                statList.add(classMethodStat);
                continue;
            }
            if(ClassHelper.checkMetodAnnotations(method,annotationClass)){
                System.out.println("开始处理类："+aClass.getSimpleName()+", 方法："+method.getName());
                long methodResLength = getMethodResLength(method);
                System.out.println("完成处理类："+aClass.getSimpleName()+", 方法："+method.getName()+", 返回值长度评估:"+methodResLength);
                classMethodStat.setReturnLength(methodResLength);
                statList.add(classMethodStat);
            }
        }
    }

    public static <A extends Annotation> void getAnnotationByMethods(String classDes,Class<?> aClass, Class<A> annotationClass, List<ApiMethodVo> statList) throws Exception {
        Method[] methods = aClass.getMethods();
        for (Method method : methods) {
            if(method.getName().startsWith("lambda") && method.getName().contains("$")){
                System.out.println("跳过代理的方法："+method.getName());
                continue;
            }
            ApiMethodVo classMethodStat = new ApiMethodVo();
            classMethodStat.setClassName(aClass.getName());
            classMethodStat.setClassSimpleName(aClass.getSimpleName());
            classMethodStat.setMethodName(method.getName());
            classMethodStat.setReturnValueType(method.getGenericReturnType().getTypeName());
            Annotation annotation = ClassHelper.getMetodAnnotations(method, annotationClass);
            if(annotation !=null ){
                System.out.println("开始处理类："+aClass.getSimpleName()+", 方法："+method.getName());
                Type[] genericParameterTypes = method.getGenericParameterTypes();
                ArrayList<String> list = new ArrayList<>();
                for (Type parameterType : genericParameterTypes) {
                    list.add(parameterType.getTypeName());
                }

                Class<? extends Annotation> annotationClz = annotation.getClass();
                Method valueMethod = annotationClz.getMethod("value");
                Object value= valueMethod.invoke(annotation);

//                if(metodAnnotations instanceof RestApiOperation){
//                }
                classMethodStat.setParams(list);
                classMethodStat.setMethodDesc(String.valueOf(value));
                classMethodStat.setClassDesc(classDes);
                statList.add(classMethodStat);
            }
        }
    }

    private static <A extends Annotation> String getClassAnnotationValue(Class<?> aClass,Class<A> annotationClass) throws Exception {
        Annotation[] annotations = aClass.getAnnotations();
        Annotation targerAnnotation=null;
        for (Annotation annotation : annotations) {
            if( annotation.annotationType().getSimpleName().equals(annotationClass.getSimpleName())){
                targerAnnotation =  annotation;
                break;
            }
        }
        if(targerAnnotation ==null){
            return "";
        }
        Class<? extends Annotation> annotationClz = targerAnnotation.getClass();
        Method valueMethod = annotationClz.getMethod("value");
        if(valueMethod!=null){
            Object value= valueMethod.invoke(targerAnnotation);
            if(value !=null){
                return String.valueOf(value);
            }
        }

       return  "";
    }

    public static long getMethodResLength(Method method) throws Exception {
        long length=0;
        recursionMap.clear();
        Type genericReturnType = method.getGenericReturnType();
        if(genericReturnType.getTypeName().equalsIgnoreCase("void")){
            return length;
        }
        //如果为含有范类型的对象
        if (genericReturnType instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) genericReturnType;
            //获得Demo1<String>，<>中的实际类型参数
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                length = length+innnerCheck(actualTypeArgument);
            }
            if(parameterizedType.getRawType().getTypeName().endsWith("ListResponse")){
                //TODO: 特殊处理
                length=length*defaultListSize+8;
                System.out.println("ListResponse 待特殊处理");
            }
            if(parameterizedType.getRawType().getTypeName().endsWith("PageResponse")){
                //TODO: 特殊处理
                length = length*defaultPageSize+24;
                System.out.println("PageResponse 待特殊处理");
            }
            if(parameterizedType.getRawType().getTypeName().endsWith("SingleData")){
                //TODO: 特殊处理
                length =length+8;
                System.out.println("SingleData 待特殊处理");
            }
            if(parameterizedType.getRawType().getTypeName().endsWith("SingleResponse")){
                //TODO: 特殊处理
                length =length+8;
                System.out.println("SingleResponse 待特殊处理");
            }
            if(parameterizedType.getRawType().getTypeName().endsWith("PageScanResponse")){
                //TODO: 特殊处理
                length =length*defaultPageSize+24;
                System.out.println("SingleResponse 待特殊处理");
            }
            return length;
            //获得参数类型
        }
        Class<?> clazz = null;
        try {
            clazz = (Class<?>) genericReturnType;
        }catch (Throwable t){
            System.out.println("不识别的类型："+genericReturnType.getTypeName());
            return length;
        }
        //TODO: 计算类中属性长度
        length = innnerCheck(clazz);;
        return length;
    }

    private static long innnerCheck(Type actualTypeArgument) throws Exception {
        long length=0;
        if (actualTypeArgument instanceof ParameterizedType) {
            if(actualTypeArgument instanceof ParameterizedTypeImpl){
                ParameterizedTypeImpl actualType = (ParameterizedTypeImpl) actualTypeArgument;
                if(actualType.getRawType().isAssignableFrom(List.class)){
                    //TODO： list 处理
                    long value = calcListOrMapRes(actualType);
                    length=length+value*defaultListSize;
                    return length;
                }
                if(actualType.getRawType().isAssignableFrom(Map.class)){
                    //TODO  MAP的处理方式
                    long value = calcListOrMapRes(actualType);
                    length=length+value*defauleMapSize;
                    return length;
                }
            }
            ParameterizedType pt = (ParameterizedType) actualTypeArgument;
            //todo:得到泛型里的class类型对象。
            Type[] ptActualTypeArguments = pt.getActualTypeArguments();
            for (Type ptActualTypeArgument : ptActualTypeArguments) {
                System.out.println(ptActualTypeArgument.getTypeName());
                length=length+innnerCheck(ptActualTypeArgument);
                continue;
            }
        }
        Class<?> clazz = null;
        try {
            clazz = (Class<?>) actualTypeArgument;
        }catch (Throwable t){
            System.out.println("不识别的类型："+actualTypeArgument.getTypeName());
            return length;
        }
        length = length+calcObjecRes(clazz);
//        if(value < 0){
//            //非基本类型，递归调用类解析方法
//            Integer integer = recursionMap.get(clazz.getSimpleName());
//            if(integer ==null && integer <=5){
//                System.out.println("二次解析："+clazz.getName());
//                length=length+ calcObjecRes(clazz);
//            }else {
//                length = length+50;
//            }
//        }else {
//            length=length+value;
//        }
        //TODO: 计算类中属性长度
//        System.out.println(clazz.getName());
        return length;
    }


    private static long calcListOrMapRes(ParameterizedTypeImpl actualType) throws Exception {
        //TODO： list 处理
        long length =0;
        Type[] listActualTypeArguments = actualType.getActualTypeArguments();
        for (Type listActualTypeArgument : listActualTypeArguments) {
            System.out.println("list:"+listActualTypeArgument.getTypeName());
            //todo: 递归循环调用获取对象长度
            length= length+innnerCheck(listActualTypeArgument);
        }
        return length;
    }



    private static long calcObjecRes(Class<?> aClass) throws Exception {
        long valueField= doCalc(aClass);
        if(valueField>=0){
            return valueField;
        }
        long length = 0;
        Field[] fields = aClass.getDeclaredFields();//获取字段信息
        for (Field f : fields) {
            Class<?> fieldClazz = f.getType();//获取f的类
            if (fieldClazz.isPrimitive()) {
                length= length + doPrimitaiveCalc(fieldClazz);
                continue;  //判断是否为基本类型
            }
            if (fieldClazz.isAssignableFrom(List.class)) {//判断fc是否和List相同或者其父类
                Type fc = f.getGenericType(); //如果是List类型，得到其Generic的类型
                if (fc instanceof ParameterizedType) {
                    ParameterizedTypeImpl pt = (ParameterizedTypeImpl) fc;
                    //得到泛型里的class类型对象。
                    long value = calcListOrMapRes(pt);
                    length=length+value*defaultListSize;
                    continue;
                }
            }
            if (fieldClazz.isAssignableFrom(Map.class)) {//判断fc是否和List相同或者其父类
                Type fc = f.getGenericType(); //如果是List类型，得到其Generic的类型
                if (fc instanceof ParameterizedType) {
                    ParameterizedTypeImpl pt = (ParameterizedTypeImpl) fc;
                    //得到泛型里的class类型对象。
                    long value = calcListOrMapRes(pt);
                    length=length+value*defauleMapSize;
                    continue;
                }
            }
            if (fieldClazz.isAssignableFrom(Object.class)) {
                continue;
            }

            long value = doCalc(fieldClazz);
            if(value<0){
                //非基本类型，递归调用类解析方法
                Integer integer = recursionMap.get(aClass.getSimpleName());
                if(integer ==null && integer <=5){
                    System.out.println("二次解析对象："+fieldClazz.getName());
                    length=length+ innnerCheck(fieldClazz);
                }else {
                    length = length+50;
                }
            }else {
                length=length+value;
            }
        }
        return length;
    }

    /**
     * * @see     java.lang.Boolean#TYPE 1/4
     * * @see     java.lang.Character#TYPE 2
     * * @see     java.lang.Byte#TYPE 1
     * * @see     java.lang.Short#TYPE  2
     * * @see     java.lang.Integer#TYPE   4
     * * @see     java.lang.Long#TYPE 8
     * * @see     java.lang.Float#TYPE 4
     * * @see     java.lang.Double#TYPE 8
     * * @see     java.lang.Void#TYPE 0
     *
     * @param aClass
     */
    static long doCalc(Class<?> aClass) {
        if(aClass.isPrimitive()){
            return doPrimitaiveCalc(aClass);
        }
        String simpleName = aClass.getSimpleName();
        long length = 0;
        if (aClass.isAssignableFrom(Boolean.class)) {
            length = length + 16;
        } else if (aClass.isAssignableFrom(Character.class)) {
            length = length + 16;
        } else if (aClass.isAssignableFrom(Byte.class)) {
            length = length + 16;
        } else if (aClass.isAssignableFrom(Short.class)) {
            length = length + 16;
        } else if (aClass.isAssignableFrom(Integer.class)) {
            length = length + 16;
        } else if (aClass.isAssignableFrom(Long.class)) {
            length = length + 24;
        } else if (aClass.isAssignableFrom(Float.class)) {
            length = length + 16;
        } else if (aClass.isAssignableFrom(Double.class)) {
            length = length + 24;
        } else if (aClass.isAssignableFrom(String.class)) {
            length = length + 50 + 4;
        } else if (aClass.isAssignableFrom(Date.class)) {
            length = length + 24;
        }else if(simpleName.endsWith("Enum") && aClass.getSuperclass().isAssignableFrom(Enum.class)){
            //TODO:枚举特殊处理
            length = length + 4+4;
        }else if(aClass.getSimpleName().endsWith("Object")){
            //Object对象统一按照20字节评估
            length = length + 20;
        }
//        else if(simpleName.endsWith("CtpResourceDto")){
//            //特殊类处理
//            length = length+13*8+17*50+3*4+4*8+7;
//        }else if(simpleName.endsWith("CtpNavMenuDto")){
//            //特殊类处理
//            length = length+4*8+15*50+3*4+3*8;
//        }
        else if (aClass.isAssignableFrom(Class.class)
                || aClass.isAssignableFrom(Constructor.class)
                || aClass.isAssignableFrom(BaseCalendar.class)) {
            return 0;
        }else{
            System.out.println("unknow class:" + simpleName);
            Integer integer = recursionMap.get(simpleName);
            if(integer ==null){
                recursionMap.put(simpleName,1);
            }else {
                if(integer>5){
                    return 100;
                }
                recursionMap.put(simpleName,integer+1);
            }
            return -1;
        }
        return length;
    }

    private  static long doPrimitaiveCalc(Class<?> aClass) {
        long length = 0;
        if (aClass.isAssignableFrom(boolean.class)) {
            length = length + 16;
        } else if (aClass.isAssignableFrom(char.class)) {
            length = length + 16;
        } else if (aClass.isAssignableFrom(byte.class)) {
            length = length + 16;
        } else if (aClass.isAssignableFrom(short.class)) {
            length = length + 16;
        } else if (aClass.isAssignableFrom(int.class)) {
            length = length + 16;
        } else if (aClass.isAssignableFrom(long.class)) {
            length = length + 24;
        } else if (aClass.isAssignableFrom(float.class)) {
            length = length + 16;
        } else if (aClass.isAssignableFrom(double.class)) {
            length = length + 24;
        }else {
            System.out.println("unknow Primitaive:" + aClass.getName());
        }
        return length;
    }


    private static void writeToFile(List<?> list,String outfile){
        List<String> collect = list.stream().map(a -> a.toString()).collect(Collectors.toList());
        FileUtil.appendLines(collect,outfile+".txt", Charset.defaultCharset());
//        writeToExcel(list,outfile+".xls");
        ExcelWriter writer = null;
        if(outfile.contains("rest")){
            writer= ExcelUtil.getWriter(baseDir+File.separator+excelName,"rest");
        }else if(outfile.contains("dubbo")){
            writer= ExcelUtil.getWriter(baseDir+File.separator+excelName,"dubbo");
        }else {
            writer= ExcelUtil.getWriter(baseDir+File.separator+excelName);
        }
// 合并单元格后的标题行，使用默认标题样式
//        writer.merge(3, "一班成绩单");
// 一次性写出内容，使用默认样式，强制输出标题
        writer.write(list, true);
// 关闭writer，释放内存
        writer.close();
    }

    private static void writeToExcel(List<ClassMethodStat> list,String outfile){
        ExcelWriter writer = ExcelUtil.getWriter(outfile);
// 合并单元格后的标题行，使用默认标题样式
//        writer.merge(3, "一班成绩单");
// 一次性写出内容，使用默认样式，强制输出标题
        writer.write(list, true);
// 关闭writer，释放内存
        writer.close();
    }


    private static List<Method> getMetohdsOutObjectMethods(Class<?> clazz){
        List<Method> objectMetohds = getObjectMethods(clazz);
        List<Method> arrayList = getObjectMethods(Object.class);
        Iterator<Method> iterator = objectMetohds.iterator();
        loop: while (iterator.hasNext()){
            Method next = iterator.next();
            for (Method method : arrayList) {
                if(method.getName().equals(next.getName())){
                    iterator.remove();
                    continue loop;
                }
            }
        }
        return objectMetohds;
    }
    private static List<Method> getObjectMethods(Class<?> clazz){
        Method[] declaredMethods = clazz.getDeclaredMethods();
        List<Method> arrayList = new ArrayList<>();
        for (Method declaredMethod : declaredMethods) {
            arrayList.add(declaredMethod);
        }
        return arrayList;
    }
}
